/***************************************************************************//**
 * GCC Linker script for Silicon Labs devices
 *******************************************************************************
 * # License
 * <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
 *******************************************************************************
 *
 * SPDX-License-Identifier: Zlib
 *
 * The licensor of this software is Silicon Laboratories Inc.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 ******************************************************************************/

{#-
  Device specific sizes and addresses. These variables describes the physical
  memory of the device.
#}
{%- set sram_addr = device_ram_addr | first | default(536870912, true) %}
{%- set sram_size = device_ram_size | first %}
{%- set flash_addr = device_flash_addr | first | default(0, true) %}
{%- set flash_size = device_flash_size | first %}
{%- set flash_page_size = device_flash_page_size | first %}
{%- set bootloader_flash_addr = '0xFE10000' | int(base=16) %}
{%- set bootloader_flash_size = device_bootloader_flash_size | sum %}

{#-
  Application specific sizes. Here we start to calculate the application view
  of the physical memory.
#}
{%- set app_flash_start = flash_addr %}
{%- set app_flash_end = flash_addr + flash_size %}
{%- set app_ram_start = sram_addr %}
{%- set app_ram_end = sram_addr + sram_size %}

{#-
  On series-2 devices we reserve the last flash page for tokens and key storage
#}
{%- if (device_series | first) == 2 %}
{%-   set app_flash_end = app_flash_end - flash_page_size %}
{%- endif %}

{#-
  Reserve space for the bootloader at the beginning of flash. Note that
  bootloader_size > 0 only for devices that place the bootloader in main flash.
  On devices where the bootloader is placed in the dedicated bootloader flash
  the bootloader_size value is 0.
#}
{%- set app_bootloader_size = bootloader_size | sum %}
{%- if app_bootloader_size > 0 %}
{%-   set app_flash_start = app_flash_start + app_bootloader_size %}
{%- endif %}

{#-
  Calculate application flash and ram size based on start and end address.
#}
{%- set app_flash_size = app_flash_end - app_flash_start %}
{%- set app_ram_size = app_ram_end - app_ram_start %}

{%- set rtt = 0 %}
{% if linker_rtt_section is defined %}
{%-   set rtt = 1 %}
{% endif %}

MEMORY
{
  FLASH   (rx)  : ORIGIN = 0x{{ '%0x' % app_flash_start }}, LENGTH = 0x{{ '%0x' % app_flash_size }}
  RAM     (rwx) : ORIGIN = 0x{{ '%0x' % app_ram_start }}, LENGTH = 0x{{ '%0x' % app_ram_size }}
}

ENTRY(Reset_Handler)

SECTIONS
{
  .aat :
  {
    KEEP(*(.aat*));
    . = ALIGN(512);
  } > FLASH

{%- if apploader_enable %}
  .text_apploader :
  {
    KEEP(*(.binapploader*))
  } > FLASH
  .text_signature :
  {
    . = ALIGN({{ flash_page_size }});
  } > FLASH
{%- endif %}

  .text :
  {
    linker_vectors_begin = .;
    KEEP(*(.vectors))
    linker_vectors_end = .;

    __Vectors_End = .;
    __Vectors_Size = __Vectors_End - __Vectors;

    linker_code_begin = .;
    *(.text*)
    linker_code_end = .;

    KEEP(*(.init))
    KEEP(*(.fini))

    /* .ctors */
    *crtbegin.o(.ctors)
    *crtbegin?.o(.ctors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
    *(SORT(.ctors.*))
    *(.ctors)

    /* .dtors */
    *crtbegin.o(.dtors)
    *crtbegin?.o(.dtors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
    *(SORT(.dtors.*))
    *(.dtors)

    *(.rodata*)
    *(.eh_frame*)
  } > FLASH

  .ARM.extab :
  {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
  } > FLASH

  __exidx_start = .;
  .ARM.exidx :
  {
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
  } > FLASH
  __exidx_end = .;
  __etext = .;

  /* Start placing output sections which are loaded into RAM */
  . = ORIGIN(RAM);

  .stack ALIGN(8) (NOLOAD):
  {
    __StackLimit = .;
    KEEP(*(.stack*))
    . = ALIGN(4);
    __StackTop = .;
    PROVIDE(__stack = __StackTop);
  } > RAM

  .noinit . (NOLOAD) :
  {
    PROVIDE(__NO_INIT__begin = .);
    *(.noinit*);
    PROVIDE(__NO_INIT__end = .);
  } > RAM
  PROVIDE(__NO_INIT_NEW__size = SIZEOF(.noinit));

  .data . : AT (__etext)
  {
    . = ALIGN(4);
    __data_start__ = .;
    *(vtable)
    *(.data*)
    . = ALIGN (4);

    PROVIDE(__ram_func_section_start = .);
    *(.ram)
    PROVIDE(__ram_func_section_end = .);

    . = ALIGN(4);
    /* preinit data */
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP(*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);

    . = ALIGN(4);
    /* init data */
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP(*(SORT(.init_array.*)))
    KEEP(*(.init_array))
    PROVIDE_HIDDEN (__init_array_end = .);

    . = ALIGN(4);
    /* finit data */
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP(*(SORT(.fini_array.*)))
    KEEP(*(.fini_array))
    PROVIDE_HIDDEN (__fini_array_end = .);

    . = ALIGN(4);
    /* All data end */
    __data_end__ = .;

  } > RAM

  .bss . :
  {
    . = ALIGN(4);
    __bss_start__ = .;
{%- if rtt == 1 %}
    *(SEGGER_RTT)
{%- endif %}
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
  } > RAM

  .heap (COPY):
  {
    __HeapBase = .;
    __end__ = .;
    end = __end__;
    _end = __end__;
    KEEP(*(.heap*))
    . = ORIGIN(RAM) + LENGTH(RAM);
    __HeapLimit = .;
  } > RAM

  __heap_size = __HeapLimit - __HeapBase;

  /* This is where we handle flash storage blocks. We use dummy sections for finding the configured
   * block sizes and then "place" them at the end of flash when the size is known. */
  .internal_storage (DSECT) : {
    KEEP(*(.internal_storage*))
  } > FLASH

  .nvm (DSECT) : {
    KEEP(*(.simee*))
  } > FLASH

  linker_storage_end = ORIGIN(FLASH) + LENGTH(FLASH);
  linker_storage_begin = linker_storage_end - SIZEOF(.internal_storage);
  linker_storage_size = SIZEOF(.internal_storage);
  linker_nvm_end = linker_storage_begin;
  linker_nvm_begin = linker_nvm_end - SIZEOF(.nvm);
  linker_nvm_size = SIZEOF(.nvm);
  __nvm3Base = linker_nvm_begin;
}
